<?php
/** Parent class for all classes working with db
*/
require_once ('lib/ierror.php');
require_once ('lib/cache.php');

class Db_Table extends IError
{
    /** DB driver
     * @var Db
     */
    var $db;

    //table name
    var $table = '';

    // table fields
    var $fields = array();

    //primary key name
    var $id = 'id';

    //@see getHash()
    var $nameField = 'title';

    /** Creates DbItems.
     * @param string $table table name
     */
    function Db_Table($table)
    {
        $this->table = _t($table);
        $this->db = Db::get(_cfg('db'));

        $sql = 'SHOW COLUMNS FROM '.$this->table;
        $info = $this->db->getHash($sql);

        foreach ($info as $field => $fieldInfo)
            $this->fields[$field] = $field;

        $this->id = key($this->fields);
    }

    /**
     * Prepares array with all table fields filled in with ''
     *
     * @return array();
     */
    function getNew()
    {
        $data = array();
        foreach ($this->fields as $field)
            $data[$field] = '';
        return $data;
    }

    /** Removes from $this->aData incorrect keys (using $this->fields by default)
     * @return true
     */
    function _filterData($data, $fields=array())
    {
        if (! $fields)
            $fields = $this->fields;
        foreach($data as $k=>$v)
        {
            if (! array_key_exists($k, $fields))
                unset($data[$k]);
        }
    }


    /**
     * Performs insert
     *
     * @param array $data key=>values to insert
     * @return int inserted id
     */
    function insert($data)
    {
        Cache::get()->setDBTableChanged($this->table);
        $this->_filterData($data);
        return $this->db->insert($this->table, $this->db->escape($data));
    }

    /**
     * Performs update of current item
     *
     * @param array $data
     * @param int $id
     * @return bool result
     */
    function update($data, $id)
    {
        Cache::get()->setDBTableChanged($this->table);
        $this->_filterData($data);
        return $this->db->update($this->table,
                        $this->db->escape($data),
                        $this->id.'="'.$id.'"');
    }

    /** 
     * Removes record by PK
     * @param int $id PK value
     * @return bool result of db->query
     */
    function delete($id)
    {
        Cache::get()->setDBTableChanged($this->table);
        $sql = 'DELETE FROM '.$this->table.' WHERE '.$this->id.'="'.$id.'"';
        return $this->db->query($sql);
    }

    /** 
     * Loads info from DB by PK
     * @param int $nId PK
     * @return mixed array - loaded data, false - not found
     */
    function find($id, $field = false)
    {
        if (!$field)
            $field = $this->id ;
        $sql = 'SELECT '.join(',', $this->fields).' FROM '.$this->table.' WHERE '.$field.'="'.$id.'"';
        return $this->db->getRow($sql);
    }

    /** 
     * Prepare 'where' statement for sql query
     * @param array $cond conditions
     * @param array $map mapping like array('name'=>'p.product_name', 'price'=>'p2o.price')
     * @return string where ststement like 1 AND p.product_name LIKE "zz%" AND p2o.price < 12
     */
    function _parseWhere($cond, $map)
    {
        $pairs = array('1');
        foreach ($cond as $k => $expr)
        {
            if (is_numeric($k))
                $pairs[] = $expr;
            elseif (isset($map[$k]))
                $pairs[] = $map[$k].' '.$expr;
        }
        return join(' AND ', $pairs);
    }

    /** 
     * Prepare list of fields for select sql query
     * @param  array $map
     * @return string
     */
    function _joinFields($map)
    {
        $pairs = array();
        foreach($map as  $alias => $field )
            $pairs[] = $field . ' AS ' . $alias;
        return join(', ', $pairs);
    }
    
    /**
     * Counts number of records by condition
     *
     * @param array $where conditions
     * @return int count
     */
    function countBy($where)
    {
        $map = $this->fields;

        $where = $this->_parseWhere($where, $map);
        $sql = 'SELECT COUNT(*) FROM ' . $this->table . ' WHERE ' . $where;
        return $this->db->getField($sql);       
    }

    /** 
     * Select from DB list of records.
     * @param array $where   conditions(usually prepared by Filter class)
     * @param int   $pager   instanse of Pager object
     * @param int   $sorter  instanse of Sorter object
     * @return array $rows  found rows
     */
    function findBy($where,$pager,$sorter)
    {
        $map = $this->fields;

        $where = $this->_parseWhere($where, $map);
        $sql = 'SELECT COUNT(*) FROM ' . $this->table . ' WHERE ' . $where;
        $cnt = $this->db->getField($sql);
        if (!$cnt)
            return array();
        if ($pager){
            if (is_object($pager))
                $limit = $pager->init($cnt);
            else 
                $limit = $pager;
        }
        //$limit = ($pager ? $pager->init($cnt) : '');
        if ($sorter){
            if (is_object($sorter))
                $order = $sorter->init(array_keys($map));
            else
                $order = $sorter;
        }
        //$order = ($sorter ? : '');

        $sql = 'SELECT ' . $this->_joinFields($map)
             .  ' FROM ' . $this->table
             .  ' WHERE ' . $where;
        if ($order)
            $sql .= ' ORDER BY ' . $order;
        if ($limit)
            $sql .= ' LIMIT ' . $limit;
        $rows = $this->db->getRows($sql);

        return $rows;
    }

    /** Gets hash
    * @return hash of $this->id => $this->nameField
    */
    function getHash()
    {
        $sql = 'SELECT '.$this->id.','.$this->nameField.
                ' FROM '.$this->table.
                ' ORDER BY 2';
        return $this->db->getHash($sql);
    }
	
	/**
	 * _parseOrder
	 * This function returns sorting conditions.
	 *
	 * @param array $order
	 * @return string
	 */
    public function _parseOrder($order)
    {
        if (is_array($order) && sizeof($order) > 0)
            return "ORDER BY ".join(',',$order);
        return "";
    }
}
?>